package pl.wroc.uni.ii.evolution.utils;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
 * A utility class. Provides some additional operations to that of the Random.
 * <p>
 * Please avoid using the static instance. It makes code harder to test. Take
 * randomizer as a parameter to the constructor if you can (at least provide one
 * that does.
 */
public class EvRandomizer extends Random implements EvIRandomizer {

  private static final long serialVersionUID = -5352528771281646967L;
  public static final EvRandomizer INSTANCE = new EvRandomizer();
  
  public EvRandomizer() {}
  public EvRandomizer(int seed) {
  	super(seed);
  }
  
  public EvRandomizer(long seed) {
	  	super(seed);
	  }
  
  /** 
   * 
   * @param probability probability of choosing <code>true</code>
   * @return random bit
   */
  public boolean nextProbableBoolean(double probability) {
    if(nextDouble() < probability)
      return true;
    return false;
  }
  
  public int nextInt(int max) {
    return super.nextInt(max);
  }
 
  /**
   * Returns a random Integer in given interval [start, end) or [start, end]
   * @param start start of interval
   * @param end end of interval
   * @param end_inclusive specify treatment of interval's end
   * @return random int
   */
  public int nextInt(int start, int end, boolean end_inclusive) {
    return nextInt(end - start + (end_inclusive ? 1:0)) +  start;
  }
  
  /**
   * Returns a random Integer in given interval [start, end)
   * @param start start of interval (inclusive
   * @param end end of interval (exclusive)
   * @return random int
   */
  public int nextInt(int start, int end) {
    return nextInt(start, end, false);
  }
  
  /**
   * Returns an array of <code>count</code> distinct integers from given
   * interval <code>[start, end)</code>.
   * @param start start of interval (inclusive)
   * @param end end of interval (exclusive)
   * @param count returned list's length
   * @return list of distinct integers of length <code>count</code>
   */
  public int[] nextIntList(int start, int end, int count) {
    int[] list = new int[count];
    int interval_len = end - start;
    int k = 0;
    
    if(start > end) {
      throw new IllegalArgumentException("Interval's start greater than end");
    }
    
    boolean[] bool_list = nextBooleanList(interval_len, count);
   
    for(int i = 0; i < bool_list.length; i++) {
      if(bool_list[i]) {
        list[k++] = start + i;
      }
    }
    
    return list;
  }
  

  /**
   * Creates random array of <code>size</code> boolean values with exactly 
   * <code>count</code> set to true.
   * 
   * @param size returned array size
   * @param count number of <code>true</code> values in returned array
   * @return array of <code>boolean</code>s with <code>count</code>
   * uniformly distributed <code>true</code> values
   */
  public boolean[] nextBooleanList(int size, int count) {
    boolean[] list = new boolean[size];
    
    if(size < count) {
      throw new IllegalArgumentException("Interval length greater than expected list's length");
    }
    
    List<Integer> tmp = new ArrayList<Integer>();
    
    /** init **/
    for (int i = 0; i < size; i++) {
      list[i] = false;
      tmp.add(i);
    }
    
    /** select count number of  index in list arrray **/ 
    for (int i = 0; i < count; i++) {  
      int pos = EvRandomizer.INSTANCE.nextInt(tmp.size());
      list[tmp.get(pos)] = true;
      tmp.remove(pos);
    }
    
    return list;
  }
}
